package com.example.demo.service.impl;

import com.example.demo.dto.EmailSexBeanDTO;
import com.example.demo.entity.TRole;
import com.example.demo.entity.TUser;
import com.example.demo.mapper.TRoleMapper;
import com.example.demo.mapper.TUserMapper;
import com.example.demo.service.TUserService;
import com.example.demo.service.db.TUserDBService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 测试t_user服务实现类
 *
 * @author tulc
 */
@Slf4j
@Service
public class TUserServiceImpl implements TUserService {

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Autowired
    private TUserDBService tUserDBService;

    /**
     * 查用户信息
     */
    @Override
    public List<TUser> selectTUserInfo(String body) {
        List<TUser> tUsers = tUserDBService.testResultMap();
        return tUsers;
    }

    /**
     * 测试主键返回
     */
    @Override
    public String testKeyGenerate() {
        TUser tUser = new TUser();
        tUser.setUserName("测试001");
        tUser.setRealName("测试");
        tUser.setSex(new Byte("1"));
        tUser.setMobile("13590478196");
        tUser.setEmail("2285389867@qq.com");
        tUser.setNote("测试数据001");
        tUserDBService.testKeyGenerate(tUser);
        return String.valueOf(tUser.getId());
    }

    /**
     * 测试主键返回02
     */
    @Override
    public String testKeyGenerate02() {
        TUser tUser = new TUser();
        tUser.setUserName("测试002");
        tUser.setRealName("测试");
        tUser.setSex(new Byte("2"));
        tUser.setMobile("13590478196");
        tUser.setEmail("2285389867@qq.com");
        tUser.setNote("测试数据002");
        tUserDBService.testKeyGenerate02(tUser);
        return String.valueOf(tUser.getId());
    }

    /**
     * 动态sql测试
     */
    @Override
    public String testDynamicSql() {
        // 测试test标签
//        this.testSetTag();

        // 测试trim标签
//        this.testTrimTag();
        return "测试成功";
    }

    /**
     * 测试批量插入
     */
    public void testBatchInsert() {
        // 批量查询
        String[] names = new String[]{"lison","james","cindy"};
        List<TUser> users = tUserDBService.selectForeach4In(names);
        for (TUser tUser : users) {
            tUser.setNote("批量插入测试");
            System.out.println(tUser);
        }
        if (CollectionUtils.isEmpty(users)){
            System.out.println("待插入的数据为空");
            return;
        }
        int i = tUserDBService.insertForeach4Batch(users);
        users.forEach(user -> {
            System.out.println(user);
        });
    }

    /**
     * 测试批量插入02
     *    ExecutorType.BATCH方式
     */
    public void testBatchInsert02() {
//        openSession方法的ExecutorType类型的参数，枚举类型:
//        ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情（这是默认装配的）。它为每个语句的执行创建一个新的预处理语句。
//        ExecutorType.REUSE: 这个执行器类型会复用预处理语句。
//        ExecutorType.BATCH: 这个执行器会批量执行所有更新语句

//        批量操作我们是使用MyBatis提供的BatchExecutor进行的，他的底层就是通过jdbc攒sql的方式进行的。我们可以让他攒够一定数量后发给数据库一次。
        // 1.获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH,true);
        try {
            // 2.获取对应mapper
            TUserMapper tUserMapper = sqlSession.getMapper(TUserMapper.class);
            long start = System.currentTimeMillis();
            List<TUser> deptList = new ArrayList<TUser>();
            for (int i = 0; i <1000000; i++) {
                TUser tUser = new TUser("mark", "毛毛" + i, (byte) 1, "18695988747",
                        "xxoo@163.com", "mark's note");
                tUserMapper.insertSelective(tUser);
            }
            long end =System.currentTimeMillis();
            System.out.println("耗时:"+(end-start));
            //BATCH批量耗时 耗时:822
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.commit();
            sqlSession.close();
        }

    }

    /**
     * 测试批量插入03
     *    ExecutorType.BATCH方式02
     */
    public void testBatchInsert03() {
//        openSession方法的ExecutorType类型的参数，枚举类型:
//        ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情（这是默认装配的）。它为每个语句的执行创建一个新的预处理语句。
//        ExecutorType.REUSE: 这个执行器类型会复用预处理语句。
//        ExecutorType.BATCH: 这个执行器会批量执行所有更新语句

//        批量操作我们是使用MyBatis提供的BatchExecutor进行的，他的底层就是通过jdbc攒sql的方式进行的。我们可以让他攒够一定数量后发给数据库一次。
        // 1.获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH,true);
        try {
            // 2.获取对应mapper
            TUserMapper tUserMapper = sqlSession.getMapper(TUserMapper.class);
            long start = System.currentTimeMillis();
            List<TUser> deptList = new ArrayList<TUser>();
            for (int i = 0; i <1000000; i++) {
                TUser tUser = new TUser("mark", "毛毛" + i, (byte) 1, "18695988747",
                        "xxoo@163.com", "mark's note");
                deptList.add(tUser);
                if (i % 100 == 0){
                    tUserMapper.insertForeach4Batch(deptList);
                    deptList.clear();
                }
            }
            long end =System.currentTimeMillis();
            System.out.println("耗时:"+(end-start));
            //BATCH批量耗时 耗时:822
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.commit();
            sqlSession.close();
        }

    }

    /**
     * 测试关联查询
     *     1对1两种关联方式
     */
    public List<TUser> testOneToOne() {
        try {
            // 获取sqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 获取对应mapper
            TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);
            // 执行查询语句并返回结果
            List<TUser> list1 = mapper.selectUserPosition01();
            for (TUser tUser : list1) {
                System.out.println(tUser);
            }


            List<TUser> list2 = mapper.selectUserPosition02();
            System.out.println("------------主查询结束-------------");
            ObjectMapper om = new ObjectMapper().disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
            for (TUser tUser : list2) {
                System.out.println(tUser.getPosition());
                System.out.println(om.writeValueAsString(tUser));
            }

            List<TUser> resultList = new ArrayList<>();
            resultList.addAll(list1);
            resultList.addAll(list2);
            return resultList;
        } catch (Exception e) {
            log.info("#testOneToOne# exception",e);
        }

        return null;
    }

    /**
     * 多参数查询
     *    三种方式：
     *       1、map
     *       2、@param注解
     *       3、实体
     */
    public void testManyParamQuery() {
        // 2.获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 3.获取对应mapper
        TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);
        String email = "qq.com";
        Byte sex = 1;

        // 第一种方式使用map
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("email", email);
        params.put("sex", sex);
        List<TUser> list1 = mapper.selectByEmailAndSex01(params);
        System.out.println(list1.size());

        // 第二种方式直接使用参数
        List<TUser> list2 = mapper.selectByEmailAndSex02(email, sex);
        System.out.println(list2.size());

        // 第三种方式用对象
        EmailSexBeanDTO esb = new EmailSexBeanDTO();
        esb.setEmail(email);
        esb.setSex(sex);
        List<TUser> list3 = mapper.selectByEmailAndSex03(esb);
        System.out.println(list3.size());
    }

    /**
     * 测试一对多
     */
    // 1对多两种关联方式
    public List<TUser> testOneToMany() {
        // 2.获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 3.获取对应mapper
        TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);
        // 4.执行查询语句并返回结果
        // ----------------------
        List<TUser> selectUserJobs01 = mapper.selectUserJobs01();
        List<TUser> selectUserJobs02 = mapper.selectUserJobs02();
        for (TUser tUser : selectUserJobs01) {
            System.out.println(tUser);
        }
        for (TUser tUser : selectUserJobs02) {
            System.out.println(tUser.getJobs().size());
        }

        List<TUser> userList = new ArrayList<>();
        userList.addAll(selectUserJobs01);
        userList.addAll(selectUserJobs02);
        return userList;
    }

    /**
     * 多对多查询
     *
     * 两种方式：
     *    1、嵌套结果
     *    2、嵌套查询
     */
    public List<TUser> testManyToMany() {
        // 2.获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 3.获取对应mapper
        TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);
        // 4.执行查询语句并返回结果
        // ----------------------
        // 方式一：嵌套结果
        List<TUser> list = mapper.selectUserRole();
        for (TUser tUser : list) {
            System.out.println(tUser.getRoles().size());
        }

        // 方式二：嵌套查询
        TRoleMapper roleMapper = sqlSession.getMapper(TRoleMapper.class);
        List<TRole> roles = roleMapper.selectRoleAndUsers();
        System.out.println("================主表查询结束=====================");
        for (TRole tRole : roles) {
            System.out.println(tRole.getUsers());
        }
        return list;
    }

    /**
     * 测试trim标签
     */
    private void testTrimTag() {
        TUser tUser = tUserDBService.getById(204);
        tUser.setId(null);
        tUser.setRealName("测试trim标签");
        tUser.setUserName("测试trim标签");
        tUser.setNote("测试trim标签");
        tUserDBService.insertIfAndTrimOper(tUser);
        System.out.println("trim标签测试："+tUser.getId());
    }

    /**
     * 测试test标签
     */
    private void testSetTag() {
        TUser tUser = tUserDBService.getById(203);
        tUser.setRealName("测试set标签");
        tUser.setUserName("测试set标签");
        tUser.setNote("测试set标签");
        tUserDBService.updateIfAndSetOper(tUser);
    }

}
